#include "client.h"

#define SER_IP "192.168.10.47"
#define SER_PORT 6789

#define LISTEN_MAX 100
char myname[20] = {0};
char signname[100] = {0};
char account_c[100] = {0};
char mylocalname[20]; // 用于保存传输文件来源的名字
char fsignname[40];   // 用于保存文件传输名字
int root = 0;
int flag = 1;
void *recvdata_do_handler(void *a);
/********************************************
 * TCP通信客户端流程
 * 1，创建套接字
 * 2，请求连接
 * 3，收发数据
 * 4，关闭套接字
 * *************************************************/

int main(int argc, char *argv[])
{
    // 1.创建套接字   IPV4  流式套接字  TCP协议
    int clifd = socket(AF_INET, SOCK_STREAM, 0);
    if (clifd == -1)
    {
        perror("socket");
        return -1;
    }
    printf("clifd = %d\n", clifd);

    struct sockaddr_in seraddr;
    memset(&seraddr, 0, sizeof(struct sockaddr_in));
    seraddr.sin_family = AF_INET; // ipv4协议类型
    seraddr.sin_addr.s_addr = inet_addr(SER_IP);
    seraddr.sin_port = htons(SER_PORT); // 端口    网络字节序
    // 2.请求连接
    if (connect(clifd, (struct sockaddr *)&seraddr, sizeof(struct sockaddr_in)) == -1)
    {
        perror("connect");
        return -1;
    }

    printf("连接成功\n");

    Ask_server(clifd);
    close(clifd);
    return 0;
}

void main_menu(void)
{
    system("clear");
    printf("\n\n\n\n\n\n\n\n");
    printf("+++++++++++++++++++++++++++++++++++++++++\n");
    printf("+++\t    欢迎使用101聊天室          +++\n");
    printf("+++\t\t1,注册                +++\n");
    printf("+++\t\t2,登录                +++\n");
    printf("+++\t\t3,退出                +++\n");
    printf("+++++++++++++++++++++++++++++++++++++++++\n");
}

int Ask_server(int client_socket) //主界面
{
    char ch;
    int ret;
    while (1)
    {
        main_menu(); // 引用菜单栏
        printf("请输入您要做操作\n");
        scanf("%c", &ch);
        while (getchar() != '\n')
            ;
        switch (ch)
        {
        case '1': // 注册
            regisc(client_socket);
            sleep(1);
            break;
        case '2': // 登录
            ret = entry(client_socket);
            if (ret == 1)
            {
                User_used(client_socket); // 调用函数表示用户界面
            }
            sleep(1);
            break;
        case '3': // 退出
            exit(0);
            break;
        }
    }
}
// 注册函数
void regisc(int client_socket)
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 1;
    printf("请输入用户名\n");
    scanf("%s", msg.fromname);
    while (getchar() != '\n')
        ;
    printf("请输入账号\n");
    scanf("%s", msg.account);
    while (getchar() != '\n')
        ;
    printf("请输入密码\n");
    scanf("%s", msg.password);
    while (getchar() != '\n')
        ;
    printf("请输入个性签名\n");
    scanf("%s", msg.signname);
    while (getchar() != '\n')
        ;
    send(client_socket, &msg, sizeof(msg), 0);
    recv(client_socket, &msg, sizeof(msg), 0);
    printf("%d\n", msg.cmd);
    if (msg.cmd == 1001)
    {
        printf("注册成功\n");
    }
    else if (msg.cmd == -1)
    {
        printf("用户名以存在,注册失败\n");
    }
    else
    {
        printf("系统繁忙,注册失败\n");
    }

    sleep(2);
}

// 登录账号
int entry(int client_socket)
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 2;

    printf("登录,请输入账号名: ");
    scanf("%s", msg.account);
    while (getchar() != '\n')
        ;

    printf("登录,请输入密码: ");

    scanf("%s", msg.password);
    while (getchar() != '\n')
        ;

    printf("\n");

    write(client_socket, &msg, sizeof(msg));
    memset(&msg, 0, sizeof(msg));
    read(client_socket, &msg, sizeof(msg));
    printf("%d\n", msg.cmd);
    if (msg.cmd == -1) // 表示用户不存在
    {
        printf("登录失败,系统繁忙.\n");
        sleep(2);
        return -1;
    }
    if (msg.cmd == -2) // 表示用户不存在
    {
        printf("登录失败,用户不存在.\n");
        sleep(2);
        return -2;
    }
    if (msg.cmd == -3)
    {
        printf("登录失败,用户已登录.\n");
        sleep(2);
        return -3;
    }
    if (msg.cmd == -4)
    {
        printf("登录失败,密码错误.\n");
        sleep(2);
        return -4;
    }
    if (msg.cmd == 1002)
    {
        printf("登录成功,登录中...\n");
        printf("%s %s \n", msg.fromname, msg.signname);
        strcpy(myname, msg.fromname);   // 保存在线名字
        strcpy(signname, msg.signname); // 保存个性签名
        strcpy(account_c, msg.account); // 保存账号
        root = msg.num;                 // 获取权限

        sleep(2);
        return 1;
    }
}

void user_menu(void)
{
    system("clear");
    printf("%s: %s\n", myname, signname);
    // printf("\n\n\n\n\n\n\n");
    printf("++++++++++++++++++++++++++++++++++++++++\n");
    printf("+++                                  +++\n");
    printf("+++\t   欢迎使用101聊天室             +++\n");
    printf("+++                                  +++\n");
    printf("++++++++++++++++++++++++++++++++++++++++\n");
    printf("+++\t\t1,群聊               +++\n");
    printf("+++\t\t2,私聊               +++\n");
    printf("+++\t\t3,退出登录           +++\n");
    printf("+++\t\t4,查看聊天记录       +++\n");
    printf("+++\t\t5,显示当前在线人员   +++\n");
    printf("+++\t\t6,修改个性签名       +++\n");
    printf("+++\t\t7,修改密码           +++\n");
    printf("+++\t\t8,传输文件           +++\n");
    printf("+++\t\t9,注销账号           +++\n");
    printf("+++\t\tA,管理               +++\n");
    printf("++++++++++++++++++++++++++++++++++++++++\n");
}

// 用户界面
void User_used(int client_socket)
{
    // 要进行读写分离

    pthread_t read_id;
    pthread_create(&read_id, NULL, readMsg, (void *)&client_socket);
    pthread_detach(read_id); // 等待线程分离

    char ch;
    flag = 1;
    while (flag)
    {
        user_menu(); // 调用第二个用户界面
        printf("请输入您要做操作\n");
        scanf("%c", &ch);
        while (getchar() != '\n')
            ;
        switch (ch)
        {
        case '1': // 群聊
            chat_all(client_socket);
            break;
        case '2': // 私聊
            chat_one(client_socket);
            break;
        case '3': // 退出登录
            entry_out(client_socket);
            flag = 0;
            break;
        case '4': // 查看聊天记录
            look_chat();
            break;
        case '5': // 显示当前在线人数
            see_now_time(client_socket);
            break;
        case '6': // 修改个性签名
            revise_sign(client_socket);
            break;
        case '7': // 修改密码
            revise_password(client_socket);
            sleep(1);
            break;
        case '8': // 传输文件
            transfer_file(client_socket);
            break;
        case 'y': // 表示愿意接受文件
            transfer_file_y(client_socket);
            printf("接收中\n");
            getchar();
            break;
        case 'n': // 表示不愿意接受文件
            transfer_file_n(client_socket);
            sleep(1);
            break;
        case '9':
            client_logout(client_socket); // 表示注销账号
            flag = 0;
            break;
        case 'a':
            if (root == 1) // 判断是不是管理员
                client_guanli(client_socket);
            else
                printf("管理失败没有权限\n");
            sleep(1);
            break;
        }
    }

    // pthread_cancel(read_id);
}

// 读写分离专门收消息
void *readMsg(void *v)
{
    int client_socket = *((int *)v);
    Msg buf;
    time_t t;
    struct tm *pt;
    int i = 0;
    while (1)
    {
        memset(&buf, 0, sizeof(Msg));
        int ret = read(client_socket, &buf, sizeof(Msg));
        if (ret == -1)
        {
            perror("read");
            break;
        }
        switch (buf.cmd)
        {
        case 3:
            printf(" %s\n", buf.msg);
            save(&buf); // 保存聊天记录
            break;
        case 4: // 私聊

            printf(" %s\n", buf.msg);
            save(&buf); // 保存聊天记录
            break;
        case -3: // 私聊失败
            printf("私聊失败,用户不存在或下线\n");
            break;
        case 5: // 退出登录
            printf("%s 退出登录\n", buf.fromname);
            sleep(1);
            pthread_exit(NULL); // 线程退出
            break;
        case 6: // 显示当前在线人数
            printf("当前在线人员:\n");
            printf("%s\n", buf.msg);
            break;
        case 7: // 修改个性签名成功
            strcpy(signname, buf.signname);
            printf("修改个性签名成功\n");
            break;
        case -7: // 修改个性签名失败
            printf("修改个性签名失败\n");
            break;
        case 8: // 修改密码成功
            printf("修改密码成功\n");
            entry_out(client_socket);
            flag = 0;
            break;
        case -8: // 修改密码失败
            printf("修改密码失败\n");
            break;
        case 9: // 调用函数确认是否接受文件
            system("clear");
            printf("请问你是否接受来自 %s 的文件 %s(y/n)\n", buf.fromname, buf.signname);
            strcpy(mylocalname, buf.fromname); // 保存传输文件来源名字
            sleep(1);
            break;
        case -9: // 表示传输文件失败,没有找到该人
            printf("发送文件失败,好友不在线或不存在\n");
            sleep(1);
            break;
        case 10: // 表示愿意接受文件,开始传输
            start_transfer_file(client_socket);
            sleep(1);
            break;
        case -10: // 表示不愿意接受文件
            printf("发送文件失败,好友拒绝接受文件\n");
            sleep(1);
            break;
        case 11: // 接受文件
            save_transfer_file(&buf);

            break;
            // printf("%d\n",i);
        case 22:
            printf("%s\n", buf.msg);

            break;
        case 87:
            printf("禁言成功\n");
            break;
        case 88:
            printf("踢人成功\n");
            break;
        case 99:
            printf("注销成功\n");
            sleep(1);
            pthread_exit(NULL); // 线程退出
            break;
        default:
            break;
        }
    }
}

void entry_out(int client_socket) // 退出登录
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 5;
    strcpy(msg.account, account_c);
    strcpy(msg.fromname, myname);
    send(client_socket, &msg, sizeof(msg), 0);
    sleep(1);
}

void chat_all(int client_socket) // 群聊
{
    system("clear");
    Msg msg;
    time_t t;
    char senr[150];
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 3;
    strcpy(msg.fromname, myname);
    strcpy(msg.localname, "All");
    printf("输入quit退出\n");
    printf("请输入你要群发送的信息\n");
    while (1)
    {

        memset(msg.msg, 0, sizeof(msg.msg));
        memset(senr, 0, sizeof(senr));
        // getchar();
        time(&t);
        struct tm *pt = localtime(&t);
        getchar();
        printf("%d年%d月%d日 %d:%d:%d\n", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday,
               pt->tm_hour, pt->tm_min, pt->tm_sec);

        sprintf(msg.msg, "\t\t\t%d年%d月%d日 %d:%d:%d\n\t\t\t", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday,
                pt->tm_hour, pt->tm_min, pt->tm_sec);

        printf("%s:", msg.fromname);
        scanf("%s", senr);
        strcat(msg.msg, msg.fromname);
        strcat(msg.msg, ":");
        strcat(msg.msg, senr);
        while (getchar() != '\n')
            ;
        if (strcmp("quit", senr) == 0)
            break;
        write(client_socket, &msg, sizeof(Msg));
    }
    save(&msg);

    sleep(2);
}

void chat_one(int client_socket) // 私聊
{
    system("clear");
    Msg msg;
    char senr[150];
    time_t t;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 4;
    printf("请输入你要聊天的对象:\n");
    scanf("%s", msg.localname);
    while (getchar() != '\n')
        ;
    strcpy(msg.fromname, myname);
    while (1)
    {
        getchar();
        time(&t);
        struct tm *pt = localtime(&t);
        printf("%d年%d月%d日 %d:%d:%d\n", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday,
               pt->tm_hour, pt->tm_min, pt->tm_sec);
        sprintf(msg.msg, "\t\t\t%d年%d月%d日 %d:%d:%d\n\t\t\t", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday,
                pt->tm_hour, pt->tm_min, pt->tm_sec);

        printf("%s:", msg.fromname);
        scanf("%s", senr);
        while (getchar() != '\n')
            ;
        if (strcmp("quit", senr) == 0)
        {
            break;
        }

        strcat(msg.msg, msg.fromname);
        strcat(msg.msg, ":");
        strcat(msg.msg, senr);

        write(client_socket, &msg, sizeof(Msg));

        save(&msg); // 保存聊天记录
    }
    sleep(2);
}

void client_logout(int client_socket) // 注销
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 99;
    strcpy(msg.account, account_c);
    send(client_socket, &msg, sizeof(msg), 0);
}

void save(Msg *msg) // 保存
{
    char buf2[120];
    char ai[1050];
    memset(buf2, 0, sizeof(buf2));
    memset(ai, 0, sizeof(ai));
    if (strcmp(myname, msg->fromname) == 0)
    {
        sprintf(buf2, "../liaotianjilu/%s & %s.txt", msg->fromname, msg->localname);
    }
    else
    {
        sprintf(buf2, "../liaotianjilu/%s & %s.txt", msg->localname, msg->fromname);
    }

    int ps = open(buf2, O_WRONLY | O_CREAT | O_APPEND, 0644);
    sprintf(ai, "%s\n", msg->msg);
    write(ps, ai, strlen(ai));
    close(ps);
}

void look_chat() // 查看聊天记录
{
    char buf2[120];
    char ai[10500];
    memset(ai, 0, sizeof(ai));
    memset(buf2, 0, sizeof(buf2));
    printf("查看与谁的聊天记录：\n");
    scanf("%s", buf2);
    while (getchar() != '\n')
        ;
    sprintf(ai, "../liaotianjilu/%s & %s.txt", myname, buf2);

    int ps = open(ai, O_RDONLY);
    if (ps == -1)
    {
        printf("查看失败\n");
        sleep(1);
        return;
    }
    memset(ai, 0, sizeof(ai));
    read(ps, ai, sizeof(ai));
    printf("%s\n", ai);
    getchar();
    close(ps);
}

void see_now_time(int client_socket) // 查看在线人数
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 6;
    strcpy(msg.fromname, myname);
    write(client_socket, &msg, sizeof(Msg));

    sleep(2);
}

void client_guanli(int client_socket) // 管理
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    printf("请选择：1禁言，2踢人\n");
    int i;
    scanf("%d", &i);
    while (getchar() != '\n')
        ;
    if (i == 1)
    {
        msg.cmd = 87;
        printf("请选择要禁言的人:\n");
        see_now_time(client_socket);
        scanf("%s", msg.localname);
    }
    else if (i == 2)
    {
        msg.cmd = 88;
        printf("请选择要踢的人:\n");
        see_now_time(client_socket);
        scanf("%s", msg.localname);
    }
    else
    {
        printf("管理失败\n");
        return;
    }
    strcpy(msg.fromname, myname);
    write(client_socket, &msg, sizeof(Msg));

    sleep(1);
}

// 修改个性签名
void revise_sign(int client_socket)
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 7;
    printf("请输入新的个性签名:");
    scanf("%s", msg.signname);
    while (getchar() != '\n')
        ;

    strcpy(msg.fromname, myname); // 需要保存名字
    strcpy(msg.account, account_c);
    write(client_socket, &msg, sizeof(Msg));

    sleep(2);
}

// 修改密码
void revise_password(int client_socket)
{
    Msg msg;
    memset(&msg, 0, sizeof(msg));
    msg.cmd = 8;
    printf("请输入新的密码: ");
    scanf("%s", msg.password);
    while (getchar() != '\n')
        ;

    strcpy(msg.fromname, myname); // 需要保存名字
    strcpy(msg.account, account_c);
    write(client_socket, &msg, sizeof(Msg));

    sleep(2);
}

void transfer_file(int client_socket) // 传输文件
{
    Msg msg;
    msg.cmd = 9;
    printf("请输入你要传输文件的对象:");
    scanf("%s", msg.localname);
    while (getchar() != '\n')
        ;

    printf("请输入你要传输的本地文件名:");
    scanf("%s", msg.signname);
    while (getchar() != '\n')
        ;

    strcpy(msg.fromname, myname); // 需要保存名字
    write(client_socket, &msg, sizeof(Msg));

    printf("等待验收中...\n");

    strcpy(fsignname, msg.signname);
    strcpy(mylocalname, msg.localname);
    getchar();
}

// 表示愿意接受文件
void transfer_file_y(int client_socket)
{
    Msg msg;
    msg.cmd = 10;
    strcpy(msg.fromname, myname);
    strcpy(msg.localname, mylocalname);
    strcpy(mylocalname, "\0"); // 用完后置零
    write(client_socket, &msg, sizeof(Msg));
}

// 表示不愿意接受文件
void transfer_file_n(int client_socket)
{
    Msg msg;
    msg.cmd = -10;
    strcpy(msg.fromname, myname);
    strcpy(msg.localname, mylocalname);
    strcpy(mylocalname, "\0"); // 用完后置零
    write(client_socket, &msg, sizeof(Msg));
}

// 传出文件来源开始传输文件
void start_transfer_file(int client_socket)
{
    Msg msg;
    char ai[120];
    msg.cmd = 11;
    strcpy(msg.fromname, myname);
    strcpy(msg.signname, fsignname);
    strcpy(msg.localname, mylocalname);
    sprintf(ai, "../send/%s", msg.signname);
    int fd = open(ai, O_RDONLY);
    if (fd == -1)
    {
        perror("open");
        printf("传输失败\n");
        return;
    }

    int ret = 0;
    int i = 0;
    while (ret = read(fd, msg.msg, SIZE))
    {
        if (ret == -1)
        {
            perror("read");
            break;
        }
        if (ret == 0)
        {
            break;
        }
        msg.num = ret;
        write(client_socket, &msg, sizeof(Msg));
        usleep(10000); // 这个睡眠时间减缓传输速度,降低不可预祝错误出现
    }
    printf("文件复制完成传输\n");
    strcpy(fsignname, "\0");
    strcpy(mylocalname, "\0");

    close(fd);
}

// 接受文件
void save_transfer_file(Msg *buf)
{
    char ai[120];
    sprintf(ai, "../recv/%s", buf->signname);
    int fd = open(ai, O_WRONLY | O_CREAT | O_APPEND, 0777);
    write(fd, buf->msg, buf->num);
    if (buf->num != SIZE)
    {
        printf("文件接受完成\n");
    }
    close(fd);
}